package basic

import (
	"encoding/json"
	"fmt"
	"log"
	"math"
	"reflect"
	"time"

	"unsafe"

	//_ "rpc_demo" //不import的包不会执行init()

	"sort"
)

//程序的初始化顺序：先初始化包级别（package-level）的变量，当然被import进来的包要先初始化，有依赖顺序的先初始化被依赖的。每一个go文件里面可以有多个init函数，当程序启动的时候，这些init函数就按照他们的声明顺序依次执行。
func init() {
	fmt.Println("init basic")
}

//=============================

func _log(a ...interface{}) {
	fmt.Println(a)
}

// Go语言所有类型都是值类型，即传递默认是通过值复制
//
// make用于内建类型（map、slice 和channel）的内存分配。new用于各种类型的内存分配。
// new(T)分配了零值填充的T类型的内存空间，并且返回其地址，即一个*T类型的值。
// make(T, args)只能创建slice、map和channel，并且返回一个有初始值(非零)的T类型（引用），而不是*T。
// 例如，一个slice，是一个包含指向数据（内部array）的指针、长度和容量的三项描述符；在这些项目被初始化之前，slice为nil。对于slice、map和channel来说，make初始化了内部的数据结构，填充适当的值，返回初始化后的（非零）值。
func main() {
	//pointer_demo()

	//struct_demo()

	//slice_demo()

	//range_demo()

	//map_demo()

	//closure_demo()

	//func_demo()

	//tag_demo()

	//struct_hierarchy_demo()

	//method_receiver_demo()

	//interface_demo()

	//select_demo()

	//reflect_demo()

	pointer_reflect_demo("wangliqiu")
}

//=================================

func Pointer_demo() {
	i := 42

	p := &i     // point to i
	_log(*p)    // read i through the pointer
	*p = *p / 7 // set i through the pointer
	_log(i)     // see the new value of i

	//执行passP()时，传入的指针是原指针的副本，函数返回时又赋了值，所以三次打印指针的内存地址是不同，但其指向地址都相同。所以go都是值传递。
	bird := &Bird{Name: "Blue"}
	fmt.Printf("调用前的Bird:\t %+v, \t内存地址：%p, 指针的内存地址: %p\n", *bird, bird, &bird)
	b := passP(bird)
	fmt.Printf("调用后的Bird:\t %+v, \t内存地址：%p, 指针的内存地址: %p\n", *b, b, &b)

	//只要赋值了，就会发生值拷贝
	var parrot1 = Bird{Name: "Blue"}
	fmt.Printf("parrot1:\t\t %+v, \t\t内存地址：%p\n", parrot1, &parrot1)
	var parrot2 = parrot1
	fmt.Printf("parrot2:\t\t %+v, \t\t内存地址：%p\n", parrot2, &parrot2)
	parrot3 := parrot1
	fmt.Printf("parrot3:\t\t %+v, \t\t内存地址：%p\n", parrot3, &parrot3)
	parrot4 := Parrot(parrot1)
	fmt.Printf("parrot4:\t\t %+v, \t\t内存地址：%p\n", parrot4, &parrot4)

	//放入channel也是值拷贝
	p1 := Bird{Name: "1"}
	ch := make(chan Bird, 2)
	fmt.Printf("p1:\t\t %+v, \t\t内存地址：%p\n", p1, &p1)
	ch <- p1
	p1.Name = "2"
	ch <- p1
	p1.Name = "3"   //因为放入channel也是值拷贝，该Name赋值不会影响刚刚放入的p1

	p2 := <-ch
	fmt.Printf("parrot:\t\t %+v, \t\t内存地址：%p\n", p2, &p2)
	p2 = <-ch
	fmt.Printf("parrot:\t\t %+v, \t\t内存地址：%p\n", p2, &p2)//虽然是值拷贝，p2地址与p1不同，但

}

type Bird struct {
	Name string
}

func passP(b *Bird) *Bird {
	b.Name = "Great" + b.Name
	fmt.Printf("调用中的Bird:\t %+v, \t内存地址：%p, 指针的内存地址: %p\n", *b, b, &b)
	return b
}

type Parrot struct {
	Name string
}



//==============================

func struct_demo() {
	type Vertex struct {
		X, Y int
	}

	v1 := Vertex{1, 2} // has type Vertex
	v1.X = 3
	v2 := Vertex{X: 1} // Y:0 is implicit
	v3 := Vertex{}     // X:0 and Y:0
	p := &Vertex{1, 2} // has type *Vertex
	p.X = 2            //编译器自动 (*p).X

	_log(v1, v2, v3, *p)

	//匿名struct
	res := struct {
		num int
	}{0}

	_log(res)
}

//===================================

//值传递
func arrayModify(array [5]int) {
	array[0] = 88
}

//引用传递
func sliceModify(slice []int) {
	slice[0] = 88
}

//array长度是固定的，array的结构为len、数据。array的长度是Type的一部分，即[10]int和[20]int的类型是不一样的。
//slice长度是不固定的，slice的结构为pointer、len、cap。其中pointer指向array的数据块。ss := make([]string, 8, 10)，其中两个数据块存nil。
func slice_demo() {
	array := [5]int{1, 2, 3, 4, 5}
	slice := []int{1, 2, 3, 4, 5}
	arrayModify(array) //[1 2 3 4 5]
	sliceModify(slice) //[88 2 3 4 5]
	_log(array)
	_log(slice)

	peaks := []Peak{
		{"Aconcagua", 22838},
		{"Denali", 20322},
		{"Kilimanjaro", 19341},
		{"Mount Elbrus", 18510},
	}
	//slice排序
	sort.Slice(peaks, func(i, j int) bool {
		return peaks[i].Elevation >= peaks[j].Elevation
	})
	fmt.Println(peaks)
}

type Peak struct {
	Name      string
	Elevation int
}

//-===============================

func range_demo() {
	pow := make([]int, 10)
	for i, v := range pow {
		fmt.Printf("index %d = %d\n", i, v)
	}
	for i := range pow {
		pow[i] = 1 << uint(i) //左移uint(i)位
	}
	for _, v := range pow {
		fmt.Printf("%d\n", v)
	}
}

//==============================================

func map_demo() {
	type Vertex struct {
		Lat, Long float64
	}

	var m map[string]Vertex

	m = map[string]Vertex{
		"Google": {
			37.42202,
			-122.08408,
		},
	}
	m["Bell Labs"] = Vertex{
		40.68433,
		-74.39967,
	}
	_log(m)

	delete(m, "Google")
	v, ok := m["Bell Labs"]
	_log(v, "ok: ", ok)
}

//======================================

//Function closures
func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func closure_demo() {
	//Functions are values
	func0 := func(x, y float64) float64 {
		return math.Sqrt(x*x + y*y)
	}
	_log(func0(3, 4))

	//NOTE: adder() return function //每个闭包中sum都是独立的
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		_log(pos(i), neg(-2*i))
	}
}

//=========================================

var nest_func func(int, int) int

func func_demo() {
	nest_func = func(x int, y int) int {
		return x + y
	}

	_log(nest_func(3, 3))
}

//==================================
//非侵入式接口（Structural Typing）的好处：
// 1. 接口由使用方按需定义，不用事前规划。自己这边只需关心提供struct哪些方法。
// 2. 不用为实现一个接口而引入该接口的包，减少耦合。
// 3. 使go标准库的继承树无意义，只需知道这个结构体实现了哪些方法，每个方法的意义。
type interface0 interface {
	method0()
}

type struct0 struct {
	num int
}

func (s *struct0) method0() {
	println("method0: ", s.num)
	println("method0: ")
}

//struct1继承内部属性的方法，所以实现了interface0接口。
type struct1 struct {
	*struct0 //struct0 *struct0
	ss int
}

func struct_hierarchy_demo() {
	s1 := struct1{&struct0{0}, 0}
	_log(s1.struct0 == nil) //true
	s1.method0()            //编译为s1.struct0.method0()
	s1.struct0.method0()
	_log(s1.struct0 == nil) //true，也就是说对于结构体struct0，其方法都是静态绑定了。
	_log(s1.struct0.num)    //若s1为struct1{}，则panic
}

//==================================

func tag_demo() {
	type User struct {
		UserId   int    `json:"user_id" bson:"user_id"`
		UserName string `json:"user_name" bson:"user_name"`
	}

	user := &User{UserId: 1, UserName: "tony"}
	j, _ := json.Marshal(user)
	fmt.Println(string(j))
	// 输出内容：{"user_id":1,"user_name":"tony"}

	// 获取tag中的内容
	t := reflect.TypeOf(user)
	field := t.Elem().Field(0)
	fmt.Println(field.Tag.Get("json"))
	// 输出：user_id
}

//=====================================

type Vertex struct {
	X, Y float64
}

//(v *Vertex) this is method receiver
//You can declare a method on any type that is declared in your package, not just struct types.
// use a pointer receiver for two reasons:
// 	to avoid copying the value on each method call (more efficient if the value type is a large struct).
//	the method can modify the value that its receiver points to.
func (v *Vertex) Abs() float64 {
	return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

func (v Vertex) Scale(f float64) {
	v.X = f
	v.Y = f
}

func method_receiver_demo() {
	v := &Vertex{3, 4}
	//v.Abs : method value  方法值
	fmt.Printf("v.Abs: %T\n", v.Abs) // func() float64
	//(*Vertex).Abs :  method expression  方法表达式，这个表达式的第一个参数就是方法的接收器参数
	fmt.Printf("(*Vertex).Abs: %T\n", (*Vertex).Abs) //func(*main.Vertex) float64

	v.Scale(5) //no effect, because Scale method receiver is Vertex, not *Vertex.
	fmt.Println(v.Abs())
}

//=====================================

type Abser interface {
	Abs() float64
}

func interface_demo() {
	var a Abser //a为实现了接口Abser的方法接收器的参数，是个不确定类型
	f := myFloat(-math.Sqrt2)
	v := Vertex{3, 4}
	myV := myVertex(Vertex{3, 4})

	a = f  // a MyFloat implements Abser
	a = &v // a *Vertex implements Abser
	//	a = v  // error, because v is a Vertex (not *Vertex) and does NOT implement Abser.
	_log(a.Abs())
	//float64(3) + myFloat(3)     //对于基础一元操作符，两个元素必须相同类型。所以该行是错误的。
	_log(myV.X) //只拥有Vertex的属性，没有Vertex的方法
}

type myFloat float64

func (f myFloat) Abs() float64 {
	if f < 0 {
		return float64(-f)
	}
	return float64(f)
}

type myVertex Vertex

//=================================

func sum(a []int, c chan int) {
	sum := 0
	for _, v := range a {
		sum += v
	}
	c <- sum // send sum to c
	fmt.Println("cap: ", cap(c))
	fmt.Println("len: ", len(c)) //当前长度
}

//make(chan int) 类似synchronous队列， make(chan int, size)类似缓冲队列。
//sends and receives block until the other side is ready.
func channel_demo() {
	a := []int{7, 2, 8, -9, 4, 0}

	//var c <-chan int      //只读单向channel
	//var c chan<- int      //只写单向channel
	c := make(chan int) //unbuffered channel
	go sum(a[:len(a)/2], c)
	go sum(a[len(a)/2:], c)
	x := <-c // receive from c
	y := <-c

	fmt.Println(x, y)
}

//=====================================

func range_on_chan_demo() {
	c := make(chan int, 10)
	//fibonacci func
	go func(n int, c chan int) {
		x, y := 0, 1
		for i := 0; i < n; i++ {
			c <- x
			x = y
			y = x + y
		}
		close(c)
	}(cap(c), c) //入参

	//The loop for i := range c receives values from the channel repeatedly until it is closed.
	for v := range c {
		fmt.Println(v)
	}
}

//===================================

func select_demo() {
	tick := time.Tick(100 * time.Millisecond)
	boom := time.After(500 * time.Millisecond)
	for {
		//A select blocks until one of its cases can run. It chooses one at random if multiple are ready.
		//The default case in a select is run if no other case is ready.	//without blocking
		select {
		case <-tick:
			fmt.Println("tick.")
		case <-boom:
			fmt.Println("BOOM!")
			return
		default:
			fmt.Println(" ... ")
			time.Sleep(50 * time.Millisecond)
		}
	}
}

//========================================
type T struct {
	A int
	B string
}

func reflect_demo() {
	t := T{1, "wangliqiu"}

	//因为&t，所以能反射修改
	ins := reflect.ValueOf(&t).Elem()
	typeOfT := ins.Type()

	ins.Field(0).SetInt(111)

	for i := 0; i < ins.NumField(); i++ {
		field := ins.Field(i)
		log.Printf("%s %s = %v\n", typeOfT.Field(i).Name, field.Type(), field.Interface())
	}

}

//======================
//Slice的运行时一个reflect.SliceHeader结构体和这个结构体中Data字段所指向的内存。
//String运行时是一个reflect.StringHeader结构体和这个结构体所指向的内存。
//指针运行时是unsafe.Pointer和uintptr。
func pointer_reflect_demo(s string) {
	fmt.Printf("pointer: %p\n", &s)

	hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
	fmt.Printf("*StringHeader: %p\n", hdr)                      //与&s相同
	fmt.Printf("uintptr: 0x%x\n", uintptr(unsafe.Pointer(hdr))) // %p打印等与0x%x  uintptr(unsafe.Pointer())
	fmt.Printf("uintptr: %x\n", hdr)                            // 根据hdr指针类型，打印对应&实例
	data := hdr.Data
	fmt.Printf("string s data: 0x%x\n", data) //注：data是uintptr类型

	bytes := toBytes(&MyStruct{1, 2})
	ss := toMyStruct(bytes)
	log.Println(*ss)
}

type MyStruct struct {
	A int
	B int
}

func toBytes(s *MyStruct) []byte {
	var x reflect.SliceHeader
	size := int(unsafe.Sizeof(*s))
	x.Len = size
	x.Cap = size
	x.Data = uintptr(unsafe.Pointer(s))
	return *(*[]byte)(unsafe.Pointer(&x)) //SliceHeader是[]byte的运行时体现
}

func toMyStruct(b []byte) *MyStruct {
	bp := (*reflect.SliceHeader)(unsafe.Pointer(&b))
	return (*MyStruct)(unsafe.Pointer(bp.Data))
}
